package cn.hunau.bookstore.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import cn.hunau.bookstore.exception.DaoException;

 

/**
 * @author  HuangBo
 *
 * 2022-01-14 15:33:42
 *
 */
public class ConnectionUtils {
	private static String username = "root";
	private static String pwd = "root";
	private static String url = "jdbc:mysql://localhost:3306/bookstore?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=UTC";

	static {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			throw new DaoException(e);
		}
	}

	private static ThreadLocal<Connection> tl = new ThreadLocal<>();

public static Connection transactionConnection() throws DaoException {
	// 1. 尝试从Tl中取数据
	Connection conn = tl.get();
	try {
		if (conn == null || conn.isClosed()) {
			conn = newConnection();
			// 将事务管理设置为手动
			conn.setAutoCommit(false);
			// 存储到ThreadLocal中
			tl.set(conn);
		}
	} catch (Exception e) {
		throw new DaoException(e);
	}
	return conn;
}

	/**
	 * 获得与数据库新链接对象
	 * 
	 * @return
	 */
	public static Connection newConnection() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(url, username, pwd);
			return conn;
		} catch (SQLException e) {
			throw new DaoException(e);
		}
	}

	public static void close(Connection conn, Statement pstm) {
		try {
			if (conn != null) {
				conn.close();
			}
			if (pstm != null) {
				pstm.close();
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}

	}

	public static void close(Connection conn) {
		close(conn, null, null);

	}

/**
 * 封装DML语句的操作,事务会进行手动管理
 */
public static void updateTransaction(String sql, Object... args) {
	Connection conn = null;
	PreparedStatement pstm = null; 
	try {
		// 使用手动管理的连接对象
		conn = ConnectionUtils.transactionConnection();
		pstm = conn.prepareStatement(sql);
		// 对占位符进行数据绑定
		if (args.length > 0) {
			for (int i = 0; i < args.length; i++) {
				pstm.setObject(i + 1, args[i]);
			}
		}
		pstm.execute();
		// 事务管理在业务层中进行 
	} catch (SQLException e) { 
		// 事务管理在业务层中进行 
		throw new DaoException(e);
	} finally {
		// 物理资源必须手动释放
		ConnectionUtils.close(null, pstm);
	}
}

	public static void commit(Connection conn) throws DaoException {
		try {
			if (conn != null) {
				conn.commit();
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}

	}

	public static void rollback(Connection conn) throws DaoException {
		try {
			if (conn != null) {
				conn.rollback();
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}

	}

/**
 * 封装DML语句的操作
 */
public static void update(String sql, Object... args) {
	Connection conn = null;
	PreparedStatement pstm = null;
	// 定义Sql语句

	try {
		conn = ConnectionUtils.newConnection();
		pstm = conn.prepareStatement(sql);
		// 对占位符进行数据绑定
		if (args.length > 0) {
			for (int i = 0; i < args.length; i++) {
				pstm.setObject(i + 1, args[i]);
			}
		}
		pstm.execute();
	} catch (SQLException e) {
		throw new DaoException(e);
	} finally {
		// 物理资源必须手动释放
		ConnectionUtils.close(conn, pstm);
	}
}

/**
 * 封装查询语句
 * 
 * @param <T>
 * @param sql  DQL语句
 * @param rowMapper 封装的结果
 * @param args 传入的参数
 * @return
 */
public static <T> T query(String sql, RowMapper<T> rowMapper, Object... args) {
	Connection conn = null;
	PreparedStatement pstm = null;
	ResultSet rs = null;
	try {
		conn = ConnectionUtils.newConnection();
		pstm = conn.prepareStatement(sql);
		// 绑定参数
		if (args.length > 0) {
			for (int i = 0; i < args.length; i++) {
				pstm.setObject(i + 1, args[i]);
			}
		}
		rs = pstm.executeQuery();
		return rowMapper.rowMapper(rs);//将结果返回。在实现层具体处理
	} catch (Exception e) {
		throw new DaoException(e.getMessage());
	} finally {
		ConnectionUtils.close(conn, pstm, rs);
	}
}

	public static void close(Connection conn, Statement pstm, ResultSet rs) {
		try {
			if (conn != null) {
				conn.close();
			}
			if (pstm != null) {
				pstm.close();
			}
			if (rs != null) {
				rs.close();
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}

	}
}
